/*
 * @Author: i@douxuefeng.cn
 * @Date: 2022-08-31 11:28:38
 * @LastEditTime: 2022-08-31 15:46:19
 * @LastEditors: i@douxuefeng.cn
 * @Description:
 * @FilePath: /go-utils/wechat/pay/app_partner.go
 */
package pay

import (
	"fmt"
	"strconv"
	"time"

	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/services/partnerpayments"
	pay_app "github.com/wechatpay-apiv3/wechatpay-go/services/partnerpayments/app"
	payments "github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
)

type appPartner struct {
	*PayConfig
}

func NewAppPartner(cfg *PayConfig) *appPartner {
	return &appPartner{cfg}
}

func (p *appPartner) PrepayOrder(prepay OrderRequest) (resp *payments.PrepayWithRequestPaymentResponse, result *core.APIResult, err error) {
	client, ctx, err := GetClient(p.PayConfig)
	if err != nil {
		return nil, nil, err
	}
	svc := pay_app.AppApiService{Client: client}
	res, result, err := svc.Prepay(ctx, pay_app.PrepayRequest{
		SpAppid:     core.String(p.SpAppid),
		SpMchid:     core.String(p.SpMchid),
		SubAppid:    core.String(p.SubAppid),
		SubMchid:    core.String(p.SubMchid),
		Description: core.String(prepay.Description),
		OutTradeNo:  core.String(prepay.OutTradeNo),
		Attach:      core.String(prepay.Attach),
		NotifyUrl:   core.String(p.Notify),
		Amount: &pay_app.Amount{
			Currency: core.String("CNY"),
			Total:    core.Int64(int64(prepay.Amount * 100)),
		},
		SceneInfo: &pay_app.SceneInfo{
			PayerClientIp: core.String(prepay.ClientIp),
		},
	})
	if err != nil {
		return nil, nil, err
	}
	resp = new(payments.PrepayWithRequestPaymentResponse)
	resp.PrepayId = res.PrepayId
	resp.TimeStamp = core.String(strconv.FormatInt(time.Now().Unix(), 10))
	nonce, err := utils.GenerateNonce()
	if err != nil {
		return nil, nil, fmt.Errorf("generate request for payment err:%s", err.Error())
	}
	resp.NonceStr = core.String(nonce)
	resp.Package = core.String("Sign=WXPay")
	message := fmt.Sprintf("%s\n%s\n%s\n%s\n", p.SpAppid, *resp.TimeStamp, *resp.NonceStr, *res.PrepayId)
	signatureResult, err := svc.Client.Sign(ctx, message)
	if err != nil {
		return nil, nil, fmt.Errorf("generate sign for payment err:%s", err.Error())
	}
	resp.Sign = core.String(signatureResult.Signature)
	resp.PartnerId = core.String(signatureResult.MchID)
	return resp, result, err
}

func (p *appPartner) QueryOrderByTransactionId(transactionId string) (resp *partnerpayments.Transaction, result *core.APIResult, err error) {
	client, ctx, err := GetClient(p.PayConfig)
	if err != nil {
		return nil, nil, err
	}
	svc := pay_app.AppApiService{Client: client}
	resp, result, err = svc.QueryOrderById(ctx, pay_app.QueryOrderByIdRequest{
		TransactionId: core.String(transactionId),
		SpMchid:       core.String(p.SpMchid),
		SubMchid:      core.String(p.SubMchid),
	})
	return
}

func (p *appPartner) QueryOrderByOutTradeNo(outTradeNo string) (resp *partnerpayments.Transaction, result *core.APIResult, err error) {
	client, ctx, err := GetClient(p.PayConfig)
	if err != nil {
		return nil, nil, err
	}
	svc := pay_app.AppApiService{Client: client}
	resp, result, err = svc.QueryOrderByOutTradeNo(ctx, pay_app.QueryOrderByOutTradeNoRequest{
		OutTradeNo: core.String(outTradeNo),
		SpMchid:    core.String(p.SpMchid),
		SubMchid:   core.String(p.SubMchid),
	})
	return
}
